/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package utils

import (
	"fmt"
	"icep/bean/param"
	"icep/common/file"
	"icep/common/logger"
	"icep/config"
	"image"
	"image/draw"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"github.com/nfnt/resize"
)

var log = logger.GetLogger("common")

var (
	cuti   *truetype.Font // 字体
	songti *truetype.Font // 字体
)

type ecUrlConfig struct {
	TemplateImageUrl,
	BoldFontUrl,
	RoutineFontUrl,
	SealImageUrl string
}

func loadConfig() *ecUrlConfig {
	dbConfig := &ecUrlConfig{}
	dbConfig.TemplateImageUrl = config.Get("icep.ecurl.template-image-url", "")
	dbConfig.BoldFontUrl = config.Get("icep.ecurl.bold-font-url", "")
	dbConfig.RoutineFontUrl = config.Get("icep.ecurl.routine-font-url", "")
	dbConfig.SealImageUrl = config.Get("icep.ecurl.seal-image-url", "")
	return dbConfig
}

func CreateEvidenceLetter(evidenceLetterParam *param.EvidenceLetterParam) error {

	urlConfig := loadConfig()
	// 根据路径打开模板文件
	templateFile, err := os.Open(urlConfig.TemplateImageUrl)
	if err != nil {
		log.Errorf("create evidence letter, open file error: %v", err)
		return err
	}
	defer templateFile.Close()
	// 解码
	templateFileImage, err := png.Decode(templateFile)
	if err != nil {
		log.Errorf("create evidence letter, decode template file error: %v", err)
		return err
	}
	// 新建一张和模板文件一样大小的画布
	newTemplateImage := image.NewRGBA(templateFileImage.Bounds())
	// 将模板图片画到新建的画布上
	draw.Draw(newTemplateImage, templateFileImage.Bounds(), templateFileImage, templateFileImage.Bounds().Min, draw.Over)

	// 粗体
	cuti, err = loadFont(urlConfig.BoldFontUrl)
	if err != nil {
		log.Errorf("create evidence letter, load font error: %v", err)
		return err
	}
	// 常规体
	songti, err = loadFont(urlConfig.RoutineFontUrl)
	if err != nil {
		log.Errorf("create evidence letter, load font error: %v", err)
		return err
	}

	// 向图片中写入文字，按照顺序传参
	writeWord2Pic(newTemplateImage, evidenceLetterParam)
	// ====================向模板中粘贴图片 begin========================
	// 		1、根据地址获取图片内容
	imageData, err := getDataByUrl(urlConfig.SealImageUrl)
	if err != nil {
		log.Errorf("根据地址获取图片失败,err:", err)
		return err
	}
	// 		2、重新调整要粘贴图片尺寸
	imageData = resize.Resize(300, 300, imageData, resize.Lanczos3)
	// 	粘贴缩略图
	draw.Draw(newTemplateImage,
		newTemplateImage.Bounds().Add(image.Pt(1025, 1700)),
		imageData,
		imageData.Bounds().Min,
		draw.Over)
	// ====================向模板中粘贴图片 结束========================
	// 保存图片
	saveFile(newTemplateImage, evidenceLetterParam.TargetFile)
	return nil
}

func writeWord2Pic(newTemplateImage *image.RGBA, depositoryLetterParam *param.EvidenceLetterParam) {
	// 向图片中写入文字
	content := freetype.NewContext()
	content.SetClip(newTemplateImage.Bounds())
	content.SetDst(newTemplateImage)
	content.SetSrc(image.Black) // 设置字体颜色
	content.SetDPI(72)          // 设置字体分辨率
	content.SetFontSize(40)     // 设置字体大小
	// 	正式写入文字
	// 参数1：要写入的文字
	// 参数2：文字坐标
	//content.SetFont(songti)
	//content.DrawString("出证编号:", freetype.Pt(281, 197))
	//content.DrawString(depositoryLetterParam.CertNumber, freetype.Pt(470, 197))
	content.SetFont(cuti)
	content.SetFontSize(100)
	content.DrawString("存证函", freetype.Pt(630, 337))
	content.SetFontSize(40)

	newY := drawElement(content, 520, "存证主体", depositoryLetterParam.EvidenceSubject)

	newY = drawElement(content, newY, "主体证件", depositoryLetterParam.SubjectId)

	newY = drawElement(content, newY, "存证平台", depositoryLetterParam.EvidencePlatform)

	newY = drawElement(content, newY, "平台运营主体", depositoryLetterParam.OperationsSubject)

	newY = drawElement(content, newY, "存证编号", depositoryLetterParam.EvidenceId)

	newY = drawElement(content, newY, "存证类型", depositoryLetterParam.EvidenceType)

	newY = drawElement(content, newY, "存证时间", depositoryLetterParam.EvidenceTime)

	newY = drawElement(content, newY, "区块链交易id", depositoryLetterParam.TxId)

	newY = drawElement(content, newY, "区块号", strconv.Itoa(depositoryLetterParam.BlockNum))

	newY = drawElement(content, newY, "区块哈希", depositoryLetterParam.BlockHash)

	newY = drawElement(content, newY, "文件哈希", depositoryLetterParam.FileHash)

}

func drawElement(content *freetype.Context, newestY int, key string, value string) int {
	if value == "" {
		return newestY
	}
	values := []string{}
	length := len(value)

	if length <= 40 {
		values = append(values, value)
	} else {
		l := length / 40
		l += 1
		for i := 0; i < l; i++ {
			if i == l-1 {
				values = append(values, value[i*40:])
			} else {
				values = append(values, value[i*40:(i+1)*40])
			}
		}
	}

	content.SetFont(cuti)
	content.DrawString(key+":", freetype.Pt(200, newestY))
	content.SetFont(songti)
	for i, value := range values {
		if i != 0 {
			newestY += 50
		}
		content.DrawString(value, freetype.Pt(560, newestY))
	}
	newestY += 100
	return newestY
}

// 根据路径加载字体文件
// path 字体的路径
func loadFont(path string) (font *truetype.Font, err error) {
	var fontBytes []byte
	fontBytes, err = ioutil.ReadFile(path) // 读取字体文件
	if err != nil {
		err = fmt.Errorf("加载字体文件出错:%s", err.Error())
		return
	}
	font, err = freetype.ParseFont(fontBytes) // 解析字体文件
	if err != nil {
		err = fmt.Errorf("解析字体文件出错,%s", err.Error())
		return
	}
	return
}

func saveFile(pic *image.RGBA, depositoryImageUrl string) {
	err := file.CreateIfNotExists(depositoryImageUrl, false)
	if err != nil {
		log.Errorf("save file error: %v", err)
	}
	dstFile, err := os.Create(depositoryImageUrl)
	if err != nil {
		log.Errorf("save file error: %v", err)
	}
	defer dstFile.Close()
	png.Encode(dstFile, pic)
}

// 根据地址获取图片内容
func getDataByUrl(url string) (img image.Image, err error) {

	if !strings.HasSuffix(url, ".jpg") &&
		!strings.HasSuffix(url, ".jpeg") &&
		!strings.HasSuffix(url, ".png") {
		err = fmt.Errorf("[%s]不支持的图片类型,暂只支持.jpg、.png文件类型", url)
		return
	}
	// 打开图片文件
	file, err := os.Open(url)
	if err != nil {
		log.Errorf("Error opening image file:", err.Error())
		return
	}
	// 关闭文件
	defer file.Close()
	if strings.HasSuffix(url, ".jpg") || strings.HasSuffix(url, ".jpeg") {
		// jgeg.decode()有问题，明明是.jpg的图片但 会报 invalid JPEG format: missing SOI marker 错误,再次调用 png.decode
		img, err = jpeg.Decode(file)
		if err != nil {
			log.Errorf("jpeg.Decode err:%s", err.Error())
			img, err = png.Decode(file)
			if err != nil {
				err = fmt.Errorf("===>png.Decode err:%s", err.Error())
				return
			}
		}
	}
	if strings.HasSuffix(url, ".png") {
		img, err = png.Decode(file)
		if err != nil {
			err = fmt.Errorf("png.Decode err:%s", err.Error())
			return
		}
	}
	return
}
